home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / BASIC / RadSlider CDEF 1.5 / RadSlider.CDEF < prev    next >
Encoding:
Text File  |  1994-11-21  |  42.5 KB  |  866 lines  |  [TEXT/ZBAS]

  1. 'RadSlider CDEF,  version 1.5
  2. 'Copyright © 1994 MarsSaxMan (Jonathan Durkee), Red Planet Software
  3. 'All Rights Reserved
  4.  
  5. 'Permission granted to distribute this source code on a non-commercial basis *provided the file is not changed
  6. 'in any way*, including the above copyright notice. For commercial distribution, contact me for permission first.
  7.  
  8. 'Jonathan Durkee
  9. '9205 Starina Way
  10. 'Sacramento, CA  95826
  11. '(916)369-0718
  12. 'AOL/eWorld:   MarsSaxMan
  13. 'You can reach me at either service  through the Internet:
  14. 'marssaxman@aol.com or marssaxman@eworld.com
  15.  
  16. 'I'm distributing this source code in hopes that you will find it useful as an example for developing your own
  17. 'CDEFs. I don't ask anything for its use - you may include the compiled, intact RadSlider in your programs
  18. 'free of charge, and you don't even have to mention my name anywhere - but I do ask that if you use the source
  19. 'code in a CDEF of your own, that you would acknowledge my help in your Read Me or wherever appropriate.
  20. 'RadSlider is not a big, fancy program, but it still does represent a substantial investment of my time.
  21.  
  22. 'In recognition of the fact that many readers of this document will not be familiar with the modern extensions
  23. 'to BASIC incorporated by FutureBASIC, the following section describes many of the less obvious commands
  24. 'and operations used in this program.
  25.  
  26. 'FUNCTIONS
  27. 'FutureBasic functions must be defined before they are called (except for a work-around which is not used
  28. 'in this program). An ENTERPROC%/EXITPROC% is a function, but one that defines the main entry point
  29. 'for a code resource. Being the main procedure, it is therefore at the bottom of the file.
  30. 'Variables are declared before the function entry, between the LOCAL statement and the LOCAL FN definition.
  31. 'The LOCAL command has two modifications: CLEAR and MODE. They can be used together.
  32. 'CLEAR LOCAL causes all local vars to be set to _nil before function code is executed. LOCAL MODE means
  33. 'that all variables are assumed to be local, and no globals are allowed.
  34. 'Though FB functions can call themselves recursively, no functions in this program do so.
  35.  
  36. 'VARIABLES
  37. 'All variables not explicitly defined as globals (DIM'ed before the END GLOBALS command) are assumed
  38. 'to be local to the function in which they are used. I have set the _dimmedVarsOnly compile flag to 
  39. 'insure that ONLY explicitly defined variables are allowed, whether local or global. Note that this program,
  40. 'being a CDEF, uses no globals.Variables are assumed to be integers unless specified otherwise. I typically
  41. 'specify variable types anyway, so recognizing variable types shouldn't be a problem.
  42. 'variable% is an integer, variable& a long integer. variable$ is a Pascal type Str255 with leading length
  43. 'byte. variable%(index%) is an array variable, with element numbers starting at zero.
  44.  
  45. 'RECORDS
  46. 'Records can be declared either by name or size in bytes. If you wanted a grafport/cgrafport
  47. 'record, you could do one of the following:
  48. 'DIM portVar.portRec
  49. 'DIM portVar.192
  50. 'I typically use the named record types because they are easier to remember, except for rectangles,
  51. 'which have no record type name. I just reserve them like this: DIM someRect.8
  52. 'If a variable points to a record (or even if it doesn't!), fields in that record (or memory area) can be
  53. 'accessed like this: pointer&.field%. This differs from ordinary records in that the "&" sign of a long
  54. 'integer is retained. The same works for handles, handle&..field%, only two periods are placed between
  55. 'the handle and the field. This is basically the same as C's -> operator.
  56. 'Records can be set equal to each other, and the entire record will be copied. For example, if you DIM'ed
  57. ' record1.recType and record2.recType, you could copy _recType bytes between them just by saying
  58. ' record1=record2. Alternatively, you can copy an arbitrary number of bytes from an address into
  59. 'any variable like this:  var;_bytes=address&. _bytes must be a constant, whether a record name, a
  60. 'constant, or just a typed-in number.
  61.  
  62. 'OTHER MISCELLANEOUS STUFF
  63. 'POKE/PEEK WORD/LONG all have shorthand versions which I use instead. %addr&,val is POKE WORD
  64. 'and &addr&,val is POKE LONG. {addr&} is short for PEEK WORD, and [addr&] is PEEK LONG.
  65. 'PSTR$(addr&) function either returns the string pointed at by addr&, or puts the string you specify
  66. 'into the string pointed at by addr&, depending on the side of the equals sign it is found on.
  67. 'You'll notice I use certain named constants a lot (constant is a name with an underscore "_" before it)
  68. '_nil = 0 of course, as does _false. _true=1, _zTrue=&FFFFFFFF (or -1), and _pTrue=&FF (or 255).
  69.  
  70. COMPILE 0,_caseInsensitive_macsBugLabels_dimmedVarsOnly_appendRes
  71. 'these compiler flags mean -
  72. '* _caseInsensitive - somevar and SOMEVAR are treated as the same variable
  73. '* _macsBugLabels - put MacsBug type text labels on functions
  74. '* _dimmedVarsOnly - variables must be declared explicitly before use
  75. '* _appendRes - append the code resource to the destination file; don't overwrite the file
  76. RESOURCES "","APPL????","CDEF",6,"RadSlider",0
  77. 'the "6" in this line is the CDEF resource ID. Change it to whatever value you find appropriate for your program.
  78. OUTPUT FILE "RadSlider Demo"
  79. 'place the compiled code resource into the file "RadSlider Demo", the demo app for the control
  80.  
  81. _fixedSize=23                                     'the control is a fixed size of this many pixels, either horz or vert, depending on which way the control goes
  82. _edgeOffset=6                                     'how many pixels between the sized rect and the slider bar edge
  83. _fillClearOffset=7                                'this many pixels in from the edge gives you the spot to clear
  84.  
  85. _outsideRoundMajor=8                              'curve values for the outside slider bar roundrect
  86. _outsideRoundMinor=12
  87. _insideRoundMajor=6                               'curve values for the inner roundrect
  88. _insideRoundMinor=8
  89.  
  90. _handleRound=4                                    'rounding value for the handle roundrects
  91. _handleEdgeOffset=4                               'how many pixels to scoot in from the left side
  92. _handleTallEdgeOffset=6
  93. _handleWideWidth=11                               'how many pixels wide is the wide part of the handle?
  94. _handleTallWidth=7                                'how many pixels wide is the tall part of the handle
  95.  
  96.  
  97. 'part constants - used to set up the pen correctly for various parts of the control
  98. _handleWideFrame=0
  99. _handleTallFrame=1
  100. _barOutsideFrame=2
  101. _barInsideFrame=3
  102. _barFill=4
  103. _barClear1=5
  104. _barClear2=6
  105. _fillClear1=7
  106. _fillClear2=8
  107. _tickMarks=9
  108. _titleText=10
  109. _valueText=11
  110.  
  111.  
  112. 'varcode constants:
  113. _useTingeColor=1                                  'use the System's tinge color for the inner fill
  114. _drawTickMarks=2                                  'draw the tick marks along top or left of the slider
  115. _drawValueText=4                                  'continuously update the control's current value
  116. '_useWFont=8                                          'this supported constant is already defined...
  117.  
  118.  
  119. _titleFont=3                                      'Geneva
  120. _titleSize=9                                      '9 point text
  121.  
  122.  
  123. 'extra cctb constants not included in FB:
  124. _cTingeLight=13
  125. _cTingeDark=14
  126.  
  127. END GLOBALS
  128.  
  129. GOTO "MainEntry"                                  'jump directly to our main entry procedure; skip & get moving
  130.  
  131. "Math Calculators"                                '*********************************************************************************************
  132.  
  133. 'This function calculates the pixel offset to the edge of the slider handle. This function is also used for
  134. 'tracking the mouse to determine what value it currently lies over (and thus where to jump the slider hande to).
  135. 'theControl& is the control handle; rectPtr& is a pointer to the control's rectangle. current% is the current
  136. 'value of the control. This value is passed as a parameter rather than extracted from the control record
  137. 'because the function may be used for determining which control value the mouse is closest to, and in
  138. 'that case the control value is in the process of being determined. orient% is a pre-calculated value
  139. 'which will always be equal to _horz or _vert, depending on the currentorientation of the slider. This
  140. CLEAR LOCAL MODE
  141. DIM handleOffset%
  142. DIM contrlRect.8
  143. LOCAL FN handleOffset(theControl&,rectPtr&,current%,orient%)
  144.   contrlRect;8=rectPtr&                           'copy out the rectangle to draw the control in
  145.   LONG IF orient%=_horz
  146.     handleOffset%=((contrlRect.right%-_handleEdgeOffset-contrlRect.left%-_handleEdgeOffset-_handleWideWidth)*current%)/(theControl&..contrlMax%-theControl&..contrlMin%)
  147.   XELSE
  148.     handleOffset%=((contrlRect.bottom%-_handleEdgeOffset-contrlRect.top%-_handleEdgeOffset-_handleWideWidth)*(theControl&..contrlMax%-current%))/(theControl&..contrlMax%-theControl&..contrlMin%)
  149.   END IF
  150. END FN=handleOffset%
  151.  
  152. 'Function is included here because it's used in 3 different places... appropriate use for a function, eh?
  153. 'it offsets the given rectangle (which it assumes is the control rectangle) if the control has text.
  154. LOCAL FN skoogieRectForTitle(theControl&,rectPtr&,dontSwapFont%)
  155.   'if we have a control title, we must adjust the control rect accordingly so the control tracking is correct.
  156.   LONG IF PEEK([theControl&]+_contrlTitle)>0      'make sure there is text in the control's title str
  157.     LONG IF dontSwapFont%=_false
  158.       CALL TEXTFONT(_titleFont)                   'Geneva 9 point text for us, please
  159.       CALL TEXTSIZE(_titleSize)
  160.       CALL TEXTFACE(0)                            'plain text
  161.       CALL TEXTMODE(_srcCopy)                     'wipe out everything underneath
  162.     END IF
  163.     LONG IF PEEK([theControl&]+_contrlTitle+1)<>13
  164.       'if the first character is NOT a return, then the title goes along the top of the slider rect.
  165.       rectPtr&.top%=rectPtr&.top%+USR FONTHEIGHT
  166.       'this forces the slider to be centered further down in its rectangle
  167.     XELSE
  168.       rectPtr&.bottom%=rectPtr&.bottom%-USR FONTHEIGHT
  169.       'scrunches the slider up to fit the text underneath
  170.     END IF
  171.   END IF
  172. END FN
  173.  
  174. "Pixel Utilities"                                 '****************************************************************************************************************************
  175.  
  176. CLEAR LOCAL MODE
  177. DIM pixDepth%,gDevHndl&
  178. LOCAL FN getPixelDepth(@rectPtr&)
  179.   'function reports the pixel depth of the main monitor
  180.   LONG IF {_ROM85} AND &C000                      'running on a Mac Plus?
  181.     pixDepth%=1                                   'then bit depth is automatically 1
  182.     'Plus does not support FN GETMAINDEVICE call so we don't bother even calling it
  183.     'because the Plus and below only have black and white graphics anyway
  184.   XELSE
  185.     gDevHndl& = FN GETMAXDEVICE(#rectPtr&)        'get main monitor, the one with the menu bar
  186.     pixDepth%= {[[[gDevHndl&]+_gdpMap]]+_pmPixelSize}
  187.     'get main graphics device, then extract the pixmap pixel size out of it
  188.   END IF
  189. END FN=pixDepth%
  190.  
  191. CLEAR LOCAL MODE
  192. DIM thePattern.8
  193. LOCAL FN setGrayPattern
  194.   'sets the pen to gray pattern, and if color, to 25%/53% gray color
  195.   thePattern.top%=43605
  196.   thePattern.left%=43605
  197.   thePattern.bottom%=43605
  198.   thePattern.right%=43605
  199.   CALL PENPAT(thePattern)
  200. END FN
  201.  
  202. CLEAR LOCAL MODE
  203. DIM theColor.RGBColor
  204. LOCAL FN setGrayColor
  205.   'sets the foreground color to dark gray & the background color to light gray
  206.   theColor.red%=49152
  207.   theColor.green%=49152
  208.   theColor.blue%=49152
  209.   CALL RGBBACKCOLOR(theColor.red%)
  210.   theColor.red%=31129
  211.   theColor.green%=31129
  212.   theColor.blue%=31129
  213.   CALL RGBFORECOLOR(theColor.red%)
  214. END FN
  215.  
  216. CLEAR LOCAL MODE
  217. DIM theColor.RGBColor
  218. LOCAL FN setNormalColors
  219.   'sets the foreground color to normal black and white
  220.   theColor.red%=65535
  221.   theColor.green%=65535
  222.   theColor.blue%=65535
  223.   CALL RGBBACKCOLOR(theColor.red%)
  224.   theColor.red%=0
  225.   theColor.green%=0
  226.   theColor.blue%=0
  227.   CALL RGBFORECOLOR(theColor.red%)
  228. END FN
  229.  
  230. LOCAL FN setColors(forePtr&,backPtr&)
  231.   'function sets foreground & background colors passed by address
  232.   CALL RGBFORECOLOR(#forePtr&)
  233.   CALL RGBBACKCOLOR(#backPtr&)
  234. END FN
  235.  
  236. CLEAR LOCAL MODE
  237. DIM aux&,ccTab&                                   'handles for  getting aux ctl colors
  238. DIM ccTabPtr&                                     'pointer to color table block
  239. DIM maxIndex%,crntIndex%
  240. DIM osErr
  241. LOCAL FN getAuxCtlColor(theControl&,theColor%,@destPtr&)
  242.   osErr=FN GETAUXCTL(theControl&,aux&)            'get the aux handle to this control
  243.   LONG IF aux&<>_nil                              'verify the handle is valid
  244.     ccTab&=aux&..acCTable&                        'get the color table for this control
  245.     LONG IF ccTab&
  246.       maxIndex%={[ccTab&]+_ctSize}                'how many entries does this color table hold?
  247.       FOR crntIndex%=0 TO maxIndex%
  248.         ccTabPtr&=[ccTab&]+_ctTable+(crntIndex%*_ctRec)
  249.         LONG IF {ccTabPtr&}=theColor%
  250.           'did we get the color we were looking for? alright, then copy it to our destination.
  251.           %destPtr&+_red,{ccTabPtr&+2}
  252.           %destPtr&+_green,{ccTabPtr&+4}
  253.           %destPtr&+_blue,{ccTabPtr&+6}
  254.         END IF
  255.       NEXT crntIndex%
  256.     XELSE                                         '{ccTab& is not valid}
  257.       FN setNormalColors                          'if we can't get custom colors, set to normal colors instead.
  258.     END IF
  259.   XELSE                                           '{aux& is not valid}
  260.     FN setNormalColors
  261.   END IF
  262. END FN
  263.  
  264. CLEAR LOCAL MODE
  265. DIM foreColor.RGBColor,backColor.RGBColor
  266. DIM tempColor&                                    'used for calculating the 50% blend in the center of the slider panel
  267. LOCAL FN setPartColor(theControl&,@oldForePtr&,@oldBackPtr&,varCode%,whichPart%)
  268.   'function sets the color for the specified part. If the control has a color table, the color table is used.
  269.   'If not, the standard black foreground/white background/gray fill colors are used. However if varCode
  270.   'has its useTingeColor bit set, that overrides the color table, and the standard tinge colors are used.
  271.   'forecolor is set up to black already - leave it alone
  272.   backColor.red%=-1:backColor.green%=-1:backColor.blue%=-1'set this to white default
  273.   
  274.   SELECT whichPart%
  275.     CASE _handleWideFrame                         'the "wide" part of the draggable handle
  276.       FN getAuxCtlColor(theControl&,_cThumbColor,backColor.red%)
  277.       FN setColors(@foreColor.red%,@backColor.red%)
  278.     CASE _handleTallFrame                         'the tall, thin part of the sliding slider handle
  279.       FN getAuxCtlColor(theControl&,_cThumbColor,backColor.red%)
  280.       FN setColors(@foreColor.red%,@backColor.red%)
  281.     CASE _barOutsideFrame                         'the outside of the slider's main body
  282.       FN getAuxCtlColor(theControl&,_cFrameColor,foreColor.red%)
  283.       FN setColors(@foreColor.red%,@backColor.red%)
  284.     CASE _barInsideFrame                          'frame inside the bar
  285.       FN getAuxCtlColor(theControl&,_cFrameColor,foreColor.red%)
  286.       FN setColors(@foreColor.red%,@backColor.red%)
  287.     CASE _barFill                                 'patterned fill within the slider bar
  288.       LONG IF (varCode% AND _useTingeColor)<>_nil
  289.         'if we're supposed to use the tinge colors, then do so
  290.         FN getAuxCtlColor(theControl&,_cTingeDark,foreColor.red%)
  291.         FN getAuxCtlColor(theControl&,_cTingeLight,backColor.red%)
  292.         FN setColors(@foreColor.red%,@backColor.red%)
  293.       XELSE
  294.         'no, don't use tinge colors; use the body color instead
  295.         FN getAuxCtlColor(theControl&,_cBodyColor,foreColor.red%)
  296.         LONG IF foreColor.red%<>-1 AND foreColor.green%<>-1 AND foreColor.blue%<>-1
  297.           'only use the body color if it is not solid white - that is the default. We don't want solid
  298.           'white, because that doesn't show up; so we use the gray color instead.
  299.           %@tempColor&+2,foreColor.red%           'put it in, unsigned
  300.           tempColor&=65535-((65535-tempColor&)/2)
  301.           backColor.red%=FN LOWORD(tempColor&)
  302.           %@tempColor&+2,foreColor.green%         'put it in, unsigned
  303.           tempColor&=65535-((65535-tempColor&)/2)
  304.           backColor.green%=FN LOWORD(tempColor&)
  305.           %@tempColor&+2,foreColor.blue%          'put it in, unsigned
  306.           tempColor&=65535-((65535-tempColor&)/2)
  307.           backColor.blue%=FN LOWORD(tempColor&)
  308.           FN setColors(@foreColor.red%,@backColor.red%)
  309.         XELSE
  310.           FN setGrayColor
  311.         END IF
  312.       END IF
  313.     CASE _barClear1                               'the clear part on the top of the slider bar
  314.       FN setColors(oldForePtr&,oldBackPtr&)
  315.     CASE _barClear2                               'the clear part on the bottom of the slider bar
  316.       FN setColors(oldForePtr&,oldBackPtr&)
  317.     CASE _fillClear1                              'the 1-pixel line between the edge of the slider bar and the inner fill (top)
  318.       FN setColors(oldForePtr&,oldBackPtr&)
  319.     CASE _fillClear2                              '1-pixel line between the edge of the slider bar and the inner fill (bottom)
  320.       FN setColors(oldForePtr&,oldBackPtr&)
  321.     CASE _tickMarks
  322.       FN getAuxCtlColor(theControl&,_cFrameColor,foreColor.red%)
  323.       FN setColors(@foreColor.red%,oldBackPtr&)
  324.     CASE _titleText,_valueText
  325.       FN getAuxCtlColor(theControl&,_cTextColor,foreColor.red%)
  326.       FN setColors(@foreColor.red%,oldBackPtr&)
  327.   END SELECT
  328. END FN
  329.  
  330. "Constructors/Deconstructors"                     '************************************************************************************************************************
  331.  
  332. LOCAL FN makeControlRegion(theControl&)
  333.   theControl&..contrlData&=FN NEWRGN
  334. END FN
  335.  
  336. LOCAL FN killControlRegion(theControl&)
  337.   IF theControl&..contrlData& THEN CALL DISPOSERGN(theControl&..contrlData&)
  338. END FN
  339.  
  340.  
  341. "Draw/Click"                                      '*********************************************************************************************************************************
  342.  
  343. `       dcb.p   'Copyright © 1994 Jonathan E. Durkee'
  344. 'this installs my copyright notice directly into the compiled code resource
  345.  
  346. CLEAR LOCAL MODE
  347. DIM tickOffset%,tickBox.8
  348. DIM numTicks%,currentTick%
  349. DIM handleOffset%
  350. LOCAL FN drawTickMarks(theControl&,@contrlRectPtr&,orient%)
  351.   'calculates and draws the tick marks for the slider.
  352.   'If horizontal, draws them sticking up along the top. If vertical, draws them on the left side.
  353.   FOR currentTick%=theControl&..contrlMin% TO theControl&..contrlMax%
  354.     tickBox;8=contrlRectPtr&
  355.     LONG IF orient%=_horz
  356.       tickBox.left%=tickBox.left%+_handleEdgeOffset+(_handleWideWidth/2)
  357.       tickBox.right%=tickBox.left%+1
  358.       tickBox.bottom%=tickBox.top%+_edgeOffset
  359.       tickBox.top%=tickBox.top%+2
  360.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,currentTick%,_horz)
  361.       CALL OFFSETRECT(tickBox.top%,handleOffset%,0)
  362.     XELSE
  363.       tickBox.top%=tickBox.top%+_handleEdgeOffset+(_handleWideWidth/2)
  364.       tickBox.bottom%=tickBox.top%+1
  365.       tickBox.right%=tickBox.left%+_edgeOffset
  366.       tickBox.left%=tickBox.left%+2
  367.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,currentTick%,_vert)
  368.       CALL OFFSETRECT(tickBox.top%,0,handleOffset%)
  369.     END IF
  370.     CALL FRAMERECT(tickBox.top%)
  371.   NEXT currentTick%
  372. END FN
  373.  
  374. CLEAR LOCAL MODE
  375. DIM theRect.8,contrlRect.8
  376. DIM handleOffset%
  377. DIM 7 valueText$                                  'used for calculating the value text offset thing
  378. LOCAL FN calcHorzRect(theControl&,contrlRectPtr&,destRectPtr&,whichRect%)
  379.   contrlRect;8=contrlRectPtr&
  380.   SELECT whichRect%
  381.     CASE _handleWideFrame                         'the "wide" part of the draggable handle
  382.       theRect;8=contrlRectPtr&
  383.       theRect.left%=theRect.left%+_handleEdgeOffset
  384.       theRect.right%=theRect.left%+_handleWideWidth
  385.       INC(theRect.top%):DEC(theRect.bottom%)
  386.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,theControl&..contrlValue%,_horz)
  387.       CALL OFFSETRECT(theRect.top%,handleOffset%,0)
  388.     CASE _handleTallFrame                         'the tall, thin part of the sliding slider handle
  389.       theRect;8=contrlRectPtr&
  390.       theRect.left%=theRect.left%+_handleTallEdgeOffset
  391.       theRect.right%=theRect.left%+_handleTallWidth
  392.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,theControl&..contrlValue%,_horz)
  393.       CALL OFFSETRECT(theRect.top%,handleOffset%,0)
  394.     CASE _barOutsideFrame                         'the outside of the slider's main body
  395.       'now draw the roundrects:
  396.       theRect;8=contrlRectPtr&
  397.       theRect.top%=theRect.top%+_edgeOffset
  398.       theRect.bottom%=theRect.bottom%-_edgeOffset
  399.     CASE _barInsideFrame
  400.       theRect;8=contrlRectPtr&
  401.       CALL INSETRECT(theRect.top%,2,8)            'groan... ugghh.... why did I do this?
  402.     CASE _barFill
  403.       theRect;8=contrlRectPtr&
  404.       CALL INSETRECT(theRect.top%,3,9)            'this is equally equivalent ugly code
  405.     CASE _barClear1
  406.       theRect;8=contrlRectPtr&
  407.       theRect.bottom%=theRect.top%+_edgeOffset
  408.     CASE _barClear2
  409.       theRect;8=contrlRectPtr&
  410.       theRect.top%=theRect.bottom%-_edgeOffset
  411.     CASE _fillClear1                              'the 1-pixel line between the edge of the slider bar and the inner fill (top)
  412.       theRect;8=contrlRectPtr&
  413.       theRect.top%=theRect.top%+_fillClearOffset
  414.       theRect.bottom%=theRect.top%+1
  415.       theRect.left%=theRect.left%+_handleEdgeOffset
  416.       theRect.right%=theRect.right%-_handleEdgeOffset
  417.     CASE _fillClear2                              '1-pixel line between the edge of the slider bar and the inner fill (bottom)
  418.       theRect;8=contrlRectPtr&
  419.       theRect.top%=theRect.bottom%-_fillClearOffset-1
  420.       theRect.bottom%=theRect.top%+1
  421.       theRect.left%=theRect.left%+_handleEdgeOffset
  422.       theRect.right%=theRect.right%-_handleEdgeOffset
  423.     CASE _titleText                               'box for the control title to go in
  424.       'this depends on whether the control title starts with a return character or not. If it does, that
  425.       'means the title is supposed to go underneath the slider bar. If not, it means the title is above
  426.       'the slider bar, as normal.
  427.       theRect;8=contrlRectPtr&
  428.       LONG IF PEEK([theControl&]+_contrlTitle+1)<>13
  429.         'if the control does NOT start with a return, then do the normal above-rect thing.
  430.         theRect.top%=theRect.top%-(USR FONTHEIGHT+1)
  431.         theRect.bottom%=theRect.top%+USR FONTHEIGHT-1
  432.       XELSE
  433.         theRect.top%=theRect.bottom%
  434.         theRect.bottom%=theRect.top%+USR FONTHEIGHT'position below the slider bar
  435.       END IF
  436.       theRect.right%=theRect.left%+FN STRINGWIDTH(theControl&..contrlTitle$)+2
  437.     CASE _valueText
  438.       'this is used to draw the control's current value on the right side of the slider title.
  439.       theRect;8=contrlRectPtr&
  440.       LONG IF PEEK([theControl&]+_contrlTitle+1)<>13
  441.         'if the control title does NOT start with a return, then do the normal above-rect thing.
  442.         theRect.top%=theRect.top%-(USR FONTHEIGHT+1)
  443.         theRect.bottom%=theRect.top%+USR FONTHEIGHT-1
  444.       XELSE
  445.         theRect.top%=theRect.bottom%
  446.         theRect.bottom%=theRect.top%+USR FONTHEIGHT'position below the slider bar
  447.       END IF
  448.       valueText$=STR$(theControl&..contrlValue%)
  449.       theRect.left%=theRect.right%-(FN STRINGWIDTH(valueText$)+2)
  450.   END SELECT
  451.   
  452.   'now copy our calculated rectangle into the destination
  453.   BLOCKMOVE @theRect,destRectPtr&,8
  454. END FN
  455.  
  456. CLEAR LOCAL MODE
  457. DIM theRect.8,contrlRect.8
  458. DIM handleOffset%
  459. DIM 7 valueText$
  460. LOCAL FN calcVertRect(theControl&,contrlRectPtr&,destRectPtr&,whichRect%)
  461.   contrlRect;8=contrlRectPtr&
  462.   SELECT whichRect%
  463.     CASE _handleWideFrame                         'the wide part of the draggable handle
  464.       theRect;8=contrlRectPtr&
  465.       theRect.top%=theRect.top%+_handleEdgeOffset
  466.       theRect.bottom%=theRect.top%+_handleWideWidth
  467.       INC(theRect.left%):DEC(theRect.right%)
  468.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,theControl&..contrlValue%,_vert)
  469.       CALL OFFSETRECT(theRect.top%,0,handleOffset%)
  470.     CASE _handleTallFrame                         'the long, thin part of the handle
  471.       theRect;8=contrlRectPtr&
  472.       theRect.top%=theRect.top%+_handleTallEdgeOffset
  473.       theRect.bottom%=theRect.top%+_handleTallWidth
  474.       handleOffset%=FN handleOffset(theControl&,contrlRectPtr&,theControl&..contrlValue%,_vert)
  475.       CALL OFFSETRECT(theRect.top%,0,handleOffset%)
  476.     CASE _barOutsideFrame
  477.       theRect;8=contrlRectPtr&
  478.       theRect.left%=theRect.left%+_edgeOffset
  479.       theRect.right%=theRect.right%-_edgeOffset
  480.     CASE _barInsideFrame
  481.       theRect;8=contrlRectPtr&
  482.       CALL INSETRECT(theRect.top%,8,2)
  483.     CASE _barFill
  484.       theRect;8=contrlRectPtr&
  485.       CALL INSETRECT(theRect.top%,9,3)
  486.     CASE _barClear1
  487.       theRect;8=contrlRectPtr&
  488.       theRect.right%=theRect.left%+_edgeOffset
  489.     CASE _barClear2
  490.       theRect;8=contrlRectPtr&
  491.       theRect.left%=theRect.right%-_edgeOffset
  492.     CASE _fillClear1
  493.       theRect;8=contrlRectPtr&
  494.       theRect.left%=theRect.left%+_fillClearOffset
  495.       theRect.right%=theRect.left%+1
  496.       theRect.top%=theRect.top%+_handleEdgeOffset
  497.       theRect.bottom%=theRect.bottom%-_handleEdgeOffset
  498.     CASE _fillClear2
  499.       theRect;8=contrlRectPtr&
  500.       theRect.left%=theRect.right%-_fillClearOffset-1
  501.       theRect.right%=theRect.left%+1
  502.       theRect.top%=theRect.top%+_handleEdgeOffset
  503.       theRect.bottom%=theRect.bottom%-_handleEdgeOffset
  504.     CASE _titleText                               'box for the control title to go in
  505.       'this depends on whether the control title starts with a return character or not. If it does, that
  506.       'means the title is supposed to go underneath the slider bar. If not, it means the title is above
  507.       'the slider bar, as normal.
  508.       theRect;8=contrlRectPtr&
  509.       LONG IF PEEK([theControl&]+_contrlTitle+1)<>13
  510.         'if the control does NOT start with a return, then do the normal above-rect thing.
  511.         theRect.top%=theRect.top%-(USR FONTHEIGHT+1)
  512.         theRect.bottom%=theRect.top%+USR FONTHEIGHT-1
  513.       XELSE
  514.         theRect.top%=theRect.bottom%
  515.         theRect.bottom%=theRect.top%+USR FONTHEIGHT'position below the slider bar
  516.       END IF
  517.       theRect.left%=theControl&..contrlRect.left%
  518.       theRect.right%=theRect.left%+FN STRINGWIDTH(theControl&..contrlTitle$)+2
  519.     CASE _valueText
  520.       'this is used to draw the control's current value on the right side of the slider title.
  521.       theRect;8=contrlRectPtr&
  522.       LONG IF PEEK([theControl&]+_contrlTitle+1)<>13
  523.         'if the control title does NOT start with a return, then do the normal above-rect thing.
  524.         theRect.top%=theRect.top%-(USR FONTHEIGHT+1)
  525.         theRect.bottom%=theRect.top%+USR FONTHEIGHT-1
  526.       XELSE
  527.         theRect.top%=theRect.bottom%
  528.         theRect.bottom%=theRect.top%+USR FONTHEIGHT'position below the slider bar
  529.       END IF
  530.       valueText$=STR$(theControl&..contrlValue%)
  531.       theRect.right%=theControl&..contrlRect.right%
  532.       theRect.left%=theRect.right%-(FN STRINGWIDTH(valueText$)+2)
  533.   END SELECT
  534.   
  535.   'now copy the newly-calculated rectangle into its destination
  536.   BLOCKMOVE @theRect,destRectPtr&,8
  537. END FN
  538.  
  539. LOCAL FN calcRect(theControl&,@contrlRectPtr&,@destRectPtr&,whichRect%,orient%)
  540.   'function just switches between the above two functions, depending on the value of orient%.
  541.   IF orient%=_horz THEN FN calcHorzRect(theControl&,contrlRectPtr&,destRectPtr&,whichRect%) ELSE FN calcVertRect(theControl&,contrlRectPtr&,destRectPtr&,whichRect%)
  542. END FN 
  543.  
  544. CLEAR LOCAL MODE
  545. DIM cntrlRect.8
  546. DIM centerRect.8                                  'stores the centered, sized version of the control
  547. DIM tempRect.8                                    'scratchpad for calculating rectangles
  548.  
  549. DIM tempRgn&
  550. DIM orient%                                       'which way is this thing oriented?
  551.  
  552. DIM oldPenState.26,oldForeColor.RGBColor,oldBackColor.RGBColor
  553. DIM oldText.8                                     'storage for old text settings
  554. DIM pixelDepth%
  555. LOCAL FN calcCtrlRgns(theControl&,destRgn&,varCode%)
  556.   'calculates a shape for the outline of the slider (to trap clicks with)
  557.   
  558.   cntrlRect;8=[theControl&]+_contrlRect
  559.   
  560.   tempRgn&=FN NEWRGN
  561.   LONG IF tempRgn&<>_nil AND destRgn&<>_nil
  562.     
  563.     oldText;8=[[theControl&]+_contrlOwner]+_txFont'save current text settings
  564.     FN skoogieRectForTitle(theControl&,@cntrlRect.top%,varCode% AND _useWFont)
  565.     
  566.     'next, we need to adjust the rectangles to fit the control correctly
  567.     LONG IF cntrlRect.right%-cntrlRect.left% > cntrlRect.bottom%-cntrlRect.top%
  568.       'if the control is bigger horizontally, then draw it horizontally.
  569.       centerRect;8=@cntrlRect.top%
  570.       centerRect.bottom%=centerRect.top%+_fixedSize'the fixed direction is vertical, in this case
  571.       CALL OFFSETRECT(centerRect.top%,0,(cntrlRect.bottom%-centerRect.bottom%)/2)'center it vertically
  572.       orient%=_horz
  573.     XELSE
  574.       'the control is not bigger horizontally, so make it a vertical control.
  575.       centerRect;8=@cntrlRect.top%
  576.       centerRect.right%=centerRect.left%+_fixedSize
  577.       CALL OFFSETRECT(centerRect.top%,(cntrlRect.right%-centerRect.right%)/2,0)'center horizontally
  578.       orient%=_vert
  579.     END IF
  580.     
  581.     'we need to calculate exactly three roundrects: the slider bar, the wide handle, and the tall handle.
  582.     
  583.     'first put the wide handle into the dest rgn
  584.     FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleWideFrame,orient%)
  585.     CALL OPENRGN
  586.     CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  587.     CALL CLOSERGN(tempRgn&)                       'we've saved the region for the wide handle rect
  588.     CALL UNIONRGN(destRgn&,tempRgn&,destRgn&)     'put the wide handle into the destination
  589.     
  590.     'second thing: exclude the tall handle from the clip region also
  591.     FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleTallFrame,orient%)
  592.     CALL OPENRGN
  593.     CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  594.     CALL CLOSERGN(tempRgn&)
  595.     CALL UNIONRGN(destRgn&,tempRgn&,destRgn&)     'add the tall handle to the destination
  596.     
  597.     'last thing: do the roundrect fro the slider body
  598.     FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barOutsideFrame,orient%)
  599.     CALL OPENRGN
  600.     LONG IF orient%=_horz
  601.       CALL FRAMEROUNDRECT(tempRect.top%,_outsideRoundMajor,_outsideRoundMinor)
  602.     XELSE
  603.       CALL FRAMEROUNDRECT(tempRect.top%,_outsideRoundMinor,_outsideRoundMajor)
  604.     END IF
  605.     CALL CLOSERGN(tempRgn&)
  606.     CALL UNIONRGN(destRgn&,tempRgn&,destrgn&)     'mix it into the destination region
  607.     
  608.     'and dispose of the temprgn:
  609.     CALL DISPOSERGN(tempRgn&)
  610.   END IF
  611.   
  612. END FN
  613.  
  614. CLEAR LOCAL MODE
  615. DIM cntrlRect.8,oldClip&
  616. DIM centerRect.8                                  'stores the centered, sized version of the control
  617. DIM tempRect.8                                    'scratchpad for calculating rectangles
  618. DIM tempClip&,mixClip&
  619.  
  620. DIM orient%                                       'which way is this thing oriented?
  621.  
  622. DIM 7 valueText$                                  'string that contains the current value of the control
  623. DIM titleRightSide%                               'for erasing above the slider bar to eliminate extra characters from the value display
  624.  
  625. DIM oldPenState.26,oldForeColor.RGBColor,oldBackColor.RGBColor
  626. DIM oldText.8                                     'save old font, size, style, and mode in this block
  627. DIM pixelDepth%
  628. LOCAL FN drawControl(theControl&,varCode%)
  629.   'simply draws the control's picture, hilited or non-hilited....
  630.   LONG IF PEEK([theControl&]+_contrlVis)
  631.     'only draw the control if it is actually visible
  632.     
  633.     cntrlRect;8=[theControl&]+_contrlRect
  634.     pixelDepth%=FN getPixelDepth(cntrlRect.top%)
  635.     
  636.     oldClip&=FN NEWRGN
  637.     tempClip&=FN NEWRGN
  638.     mixClip&=FN NEWRGN                            'two regions for making the total clip region
  639.     LONG IF oldClip&<>_nil AND tempClip&<>_nil AND mixClip&<>_nil
  640.       CALL GETCLIP(oldClip&)                      'save the old clip region - we are going to mask drawing to the control rectangle
  641.       CALL CLIPRECT(cntrlRect)                    'only allow drawing within the slider control
  642.       CALL GETPENSTATE(oldPenState)               'save pen state, so we don't screw the program up while working
  643.       LONG IF pixelDepth%>1
  644.         CALL GETFORECOLOR(oldForeColor.red%)
  645.         CALL GETBACKCOLOR(oldBackColor.red%)
  646.       END IF
  647.       oldText;8=[[theControl&]+_contrlOwner]+_txFont'save the current text settings
  648.       CALL PENNORMAL
  649.       
  650.       'now, if we have a control title, there's some stuff we need to do. Skoogie the control rectangle
  651.       'to fit the text above or below it:
  652.       FN skoogieRectForTitle(theControl&,@cntrlRect.top%,varCode% AND _useWFont)
  653.       
  654.       'next, we need to adjust the rectangles to fit the control correctly
  655.       LONG IF cntrlRect.right%-cntrlRect.left% > cntrlRect.bottom%-cntrlRect.top%
  656.         'if the control is bigger horizontally, then draw it horizontally.
  657.         centerRect;8=@cntrlRect.top%
  658.         centerRect.bottom%=centerRect.top%+_fixedSize'the fixed direction is vertical, in this case
  659.         CALL OFFSETRECT(centerRect.top%,0,(cntrlRect.bottom%-centerRect.bottom%)/2)'center it vertically
  660.         orient%=_horz
  661.       XELSE
  662.         'the control is not bigger horizontally, so make it a vertical control.
  663.         centerRect;8=@cntrlRect.top%
  664.         centerRect.right%=centerRect.left%+_fixedSize
  665.         CALL OFFSETRECT(centerRect.top%,(cntrlRect.right%-centerRect.right%)/2,0)'center horizontally
  666.         orient%=_vert
  667.       END IF
  668.       
  669.       'also need to draw the text title for this slider
  670.       LONG IF PEEK([theControl&]+_contrlTitle)>0
  671.         FN calcRect(theControl&,centerRect.top%,tempRect.top%,_titleText,orient%)
  672.         IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_titleText)
  673.         CALL MOVETO(tempRect.left%,tempRect.bottom%)
  674.         CALL DRAWSTRING(theControl&..contrlTitle$)
  675.         
  676.         'now something for the next function, which draws the control value - we must save the
  677.         'right edge of the rectangle for this text.
  678.         titleRightSide%=tempRect.right%
  679.       END IF
  680.       
  681.       'and the current value of the control, if that option is set
  682.       LONG IF (varCode% AND _drawValueText)<>_nil
  683.         FN calcRect(theControl&,centerRect.top%,tempRect.top%,_valueText,orient%)
  684.         IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_valueText)
  685.         CALL MOVETO(tempRect.left%,tempRect.bottom%)
  686.         valueText$=STR$(theControl&..contrlValue%)
  687.         CALL DRAWSTRING(valueText$)
  688.         
  689.         'now we must erase the left-over junk from the last title and value, if necessary...
  690.         tempRect.right%=tempRect.left%
  691.         tempRect.left%=titleRightSide%
  692.         CALL ERASERECT(tempRect.top%)
  693.       END IF
  694.       
  695.       
  696.       
  697.       'okay, now calculate all the rectangles and draw them.
  698.       'First task is to draw the slider handle.
  699.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_handleWideFrame)
  700.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleWideFrame,orient%)
  701.       CALL ERASEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  702.       CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  703.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_handleTallFrame)
  704.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleTallFrame,orient%)
  705.       CALL ERASEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  706.       CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  707.       
  708.       'The slider handle is now drawn. Set up the clip region so the handle is excluded from it,
  709.       'so we can now draw the slider bar etc. without flickering.
  710.       CALL RECTRGN(tempClip&,centerRect.top%)     'set it to the full control box
  711.       'first thing: exclude the wide handle thing from the clip region
  712.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleWideFrame,orient%)
  713.       CALL OPENRGN
  714.       CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  715.       CALL CLOSERGN(mixClip&)                     'we've saved the region for the wide handle rect
  716.       CALL DIFFRGN(tempClip&,mixClip&,tempClip&)  'subtract the mix clip from the temp clip
  717.       'second thing: exclude the tall handle from the clip region also
  718.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_handleTallFrame,orient%)
  719.       CALL OPENRGN
  720.       CALL FRAMEROUNDRECT(tempRect.top%,_handleRound,_handleRound)
  721.       CALL CLOSERGN(mixClip&)
  722.       CALL DIFFRGN(tempClip&,mixClip&,tempClip&)  'subtract the mix from the temp clip
  723.       'The new clip region is prepared. Now set it to the window's clip:
  724.       CALL SETCLIP(tempClip&)
  725.       
  726.       'if the appropriate varcode is set, then draw the tick marks:
  727.       LONG IF (varCode% AND _drawTickMarks)<>_nil
  728.         IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_tickMarks)
  729.         FN drawTickMarks(theControl&,centerRect.top%,orient%)
  730.         'now exclude the tickmarks from the rest of the drawing:
  731.         CALL OPENRGN
  732.         FN drawTickMarks(theControl&,centerRect.top%,orient%)
  733.         CALL CLOSERGN(mixClip&)                   'save it as mixclip
  734.         CALL DIFFRGN(tempClip&,mixClip&,tempClip&)'subtract it from the temp clip rgn
  735.         CALL SETCLIP(tempClip&)                   'now set it to the window clip region
  736.       END IF
  737.       
  738.       'We now begin to draw the slider body.
  739.       'first do the outer frame:
  740.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_barOutsideFrame)
  741.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barOutsideFrame,orient%)
  742.       LONG IF orient%=_horz
  743.         CALL FRAMEROUNDRECT(tempRect.top%,_outsideRoundMajor,_outsideRoundMinor)
  744.       XELSE
  745.         CALL FRAMEROUNDRECT(tempRect.top%,_outsideRoundMinor,_outsideRoundMajor)
  746.       END IF
  747.       'next do the inner frame & fill:
  748.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_barInsideFrame)
  749.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barInsideFrame,orient%)
  750.       LONG IF orient%=_horz
  751.         CALL FRAMEROUNDRECT(tempRect.top%,_insideRoundMajor,_insideRoundMinor)
  752.       XELSE
  753.         CALL FRAMEROUNDRECT(tempRect.top%,_insideRoundMinor,_insideRoundMajor)
  754.       END IF
  755.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_barFill)
  756.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barFill,orient%)
  757.       FN setGrayPattern
  758.       LONG IF orient%=_horz
  759.         CALL PAINTROUNDRECT(tempRect.top%,_insideRoundMajor,_insideRoundMinor)
  760.       XELSE
  761.         CALL PAINTROUNDRECT(tempRect.top%,_insideRoundMinor,_insideRoundMajor)
  762.       END IF
  763.       
  764.       
  765.       'finally, erase whatever remnants of the old slider handle picture stuck out over the edge
  766.       'of the main slider bar:
  767.       IF pixelDepth%>1 THEN FN setPartColor(theControl&,oldForeColor.red%,oldBackColor.red%,varCode%,_barClear1)
  768.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barClear1,orient%)
  769.       CALL ERASERECT(tempRect.top%)
  770.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_barClear2,orient%)
  771.       CALL ERASERECT(tempRect.top%)
  772.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_fillClear1,orient%)
  773.       CALL ERASERECT(tempRect.top%)
  774.       FN calcRect(theControl&,centerRect.top%,tempRect.top%,_fillClear2,orient%)
  775.       CALL ERASERECT(tempRect.top%)
  776.       
  777.       'and dispose of the two temporary regions:
  778.       CALL DISPOSERGN(tempClip&)
  779.       CALL DISPOSERGN(mixClip&)
  780.       CALL SETCLIP(oldClip&)
  781.       CALL SETPENSTATE(oldPenState)
  782.       BLOCKMOVE @oldText,[[theControl&]+_contrlOwner]+_txFont,8
  783.       'restore the original font, size, style, and mode of the control's owning port.
  784.       LONG IF pixelDepth%>1
  785.         CALL RGBFORECOLOR(oldForeColor.red%)
  786.         CALL RGBBACKCOLOR(oldBackColor.red%)
  787.       END IF
  788.       CALL DISPOSERGN(oldClip&)                   'trash the old clip region now that we're done storing it
  789.     END IF
  790.     
  791.   END IF
  792. END FN
  793.  
  794. CLEAR LOCAL MODE
  795. DIM clicked%
  796. DIM orient%,newValue%
  797. DIM mouseOffset%
  798. DIM mousePt.4,cntrlRect.8
  799. DIM oldText.8,swapFont%                           'storage for the old text settings
  800. LOCAL FN checkControlClick(theControl&,param&,varCode%)
  801.   'function must check to see if the mouse is in the control. If so, it tracks clicks; otherwise, it just draws.
  802.   mousePt;4=@param&
  803.   IF FN EMPTYRGN(theControl&..contrlData&) THEN FN calcCtrlRgns(theControl&,theControl&..contrlData&,varCode%)
  804.   cntrlRect;8=[theControl&]+_contrlRect
  805.   IF cntrlRect.right%-cntrlRect.left% > cntrlRect.bottom%-cntrlRect.top% THEN orient%=_horz ELSE orient%=_vert
  806.   
  807.   oldText;8=[[theControl&]+_contrlOwner]+_txFont  'save the current text settings
  808.   FN skoogieRectForTitle(theControl&,@cntrlRect.top%,varCode% AND _useWFont)
  809.   
  810.   LONG IF FN PTINRGN(mousePt.v%,theControl&..contrlData&)
  811.     'is the mouse in the region? Goodie! This means it's time to slide this slider.
  812.     
  813.     WHILE FN BUTTON
  814.       'just loop, tracking the control, until the mouse is let up.
  815.       
  816.       LONG IF orient%=_horz
  817.         mouseOffset%=mousePt.h%-cntrlRect.left%-_handleEdgeOffset-(_handleWideWidth/2)
  818.         newValue%=((theControl&..contrlMax%-theControl&..contrlMin%)*mouseOffset%) / (cntrlRect.right%-_handleEdgeOffset-cntrlRect.left%-_handleEdgeOffset-_handleWideWidth)
  819.       XELSE
  820.         mouseOffset%=(cntrlRect.bottom%-mousePt.v%-_handleEdgeOffset-(_handleWideWidth/2))
  821.         newValue%=((theControl&..contrlMax%-theControl&..contrlMin%)*mouseOffset%) / (cntrlRect.bottom%-_handleEdgeOffset-cntrlRect.top%-_handleEdgeOffset-_handleWideWidth)
  822.       END IF
  823.       IF (mouseOffset%-FN handleOffset(theControl&,@cntrlRect,newValue%,orient%))>(FN handleOffset(theControl&,@cntrlRect,newValue%+1,orient%)-mouseOffset%) THEN INC(newValue%)
  824.       'this tortuous-looking line checks to see if the mouse is closer to the next greater tick mark.
  825.       'If it is closer, it increments the newvalue.
  826.       IF newValue%<theControl&..contrlMin% THEN newValue%=theControl&..contrlMin%
  827.       IF newValue%>theControl&..contrlMax% THEN newValue%=theControl&..contrlMax%
  828.       'make sure the value stays within range there
  829.       
  830.       LONG IF newValue%<>theControl&..contrlValue%
  831.         'if the control's value has changed, then redraw it & reset its value:
  832.         theControl&..contrlValue%=newValue%
  833.         FN drawControl(theControl&,varCode%)
  834.       END IF
  835.       
  836.       CALL GETMOUSE(mousePt.v%)                   'get the mouse again, for the next cycle-through
  837.     WEND
  838.     clicked%=_inThumb                             'yes, this control was clicked.
  839.   END IF
  840.   
  841.   BLOCKMOVE @oldText,[[theControl&]+_contrlOwner]+_txFont,8'restore original font settings
  842.   
  843. END FN=clicked%
  844.  
  845. "MainEntry"
  846. DIM varCode%,theControl&,message%,param&,returnValue&
  847. ENTERPROC%(varCode%,theControl&,message%,param&)
  848.   
  849.   returnValue&=_nil                               'reset the return code
  850.   SELECT message%
  851.       'what are we supposed to do? select & act accordingly
  852.     CASE _drawCtlMsg
  853.       FN drawControl(theControl&,varCode%)
  854.     CASE _hitCtlMsg
  855.       returnValue&=FN checkControlClick(theControl&,param&,varCode%)
  856.     CASE _calcCtlMsg
  857.       FN calcCtrlRgns(theControl&,param&,varCode%)
  858.     CASE _newCtlMsg
  859.       FN makeControlRegion(theControl&)
  860.     CASE _dispCtlMsg
  861.       FN killControlRegion(theControl&)
  862.   END SELECT
  863.   
  864. EXITPROC%=returnValue&
  865.  
  866.